package com.unism.common.mybatis;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.persistence.Column;
import javax.persistence.Id;
import javax.persistence.Table;

import org.json.JSONObject;
/**
 * mybatis 所有pojo的父类
 * @author liuc
 */
public class BasePojo implements Serializable{  
  
    private static final long serialVersionUID = 20170610121361L;  
    // 用于存放POJO的列信息 
    private transient static Map<Class<? extends BasePojo>,List<String>> columnMap = new HashMap<Class<? extends BasePojo>, List<String>>();  
    /** 
     * 获取POJO对应的表名 
     * 需要POJO中的属性定义@Table(name) 
     * @return 
     */  
    public String tablename() {  
        Table table = this.getClass().getAnnotation(Table.class);  
        if(table != null)  
            return table.name();  
        else  
            throw new RuntimeException("undefine POJO @Table, need Tablename(@Table(name))");  
    }  
    /** 
     * 获取POJO中的主键字段名 
     * 需要定义@Id 
     * @return 
     */  
    public String idName() {  
        for(Field field : this.getClass().getDeclaredFields()) {  
            if(field.isAnnotationPresent(Id.class))  
                return field.getName();  
        }  
        throw new RuntimeException("undefine POJO @Id");  
    }
    public Type idType() {  
    	for(Field field : this.getClass().getDeclaredFields()) {  
            if(field.isAnnotationPresent(Id.class))  
                return field.getGenericType();  
        }  
        throw new RuntimeException("undefine POJO @Id");  
    }
    /**
     * 判断当前pojo的属性是否存在fieldname“字符串”
     * @param fieldname
     * @return
     */
    private boolean notContainField(String fieldname) {  
        try {  
            Field field = this.getClass().getDeclaredField(fieldname);  
            return notContainField(field);  
        } catch (SecurityException e) {  
            e.printStackTrace();  
        } catch (NoSuchFieldException e) {  
            e.printStackTrace();  
        } catch (IllegalArgumentException e) {  
            e.printStackTrace();  
        }  
          
        return false;  
    }  
    /** 
     * 判断当前字段属性是否存在(Field 类型)
     * @param field
     * @return
     */
    private boolean notContainField(Field field) {  
        try {  
            field.setAccessible(true);  
            return field.get(this) == null;  
        } catch (SecurityException e) {  
            e.printStackTrace();  
        } catch (IllegalArgumentException e) {  
            e.printStackTrace();  
        } catch (IllegalAccessException e) {  
            e.printStackTrace();  
        }  
        return false;  
    }
   /**
    * 
    * @param field
    * @return
    */
    public Boolean isNull(Field field) {  
    	if(Modifier.isStatic(field.getModifiers()) || Modifier.isFinal(field.getModifiers())){
    		return false;
    	}  
        Object value = null;  
        try {  
        	field.setAccessible(true);  
            value = field.get(this);
            //如果是字符串需比较null和“”其余类型只判断null
            if(value==null || value.toString().trim().equals("")){
        		return false;
        	}else{
        		return true;
        	}
        } catch (IllegalAccessException e) {  
            e.printStackTrace();  
        }
        return false;
    }  
    /** 
     * 用于计算类定义 
     * 需要POJO中的属性定义@Column(name)  
     * liuc增强对于主键属性字段的获取 2017-06-10
     */  
    public void caculationColumnList() {  
        if(columnMap.containsKey(this.getClass())){
        	return;  
        }  
        Field[] fields = this.getClass().getDeclaredFields();  
        List<String> columnList = new ArrayList<String>(fields.length);  
        for(Field field : fields) {  
            if(field.isAnnotationPresent(Column.class) || field.isAnnotationPresent(Id.class))  
                columnList.add(field.getName());  
        }  
        columnMap.put(this.getClass(), columnList);  
    }
    /**
     * 获取当前实例对应表的所有属性","分割,没有默认返回提示信息
     * @return
     */
    public String getTableField(){
    	 caculationColumnList();
    	 List<String> columnList =columnMap.get(this.getClass());
    	 StringBuilder sb = new StringBuilder();  
         Integer i = 0;  
         if(columnList==null || columnList.isEmpty()){
        	 return "liuc said that the table does not have any attributes";
         }
         for(String column : columnList) {  
             if(i++ != 0){
            	  sb.append(',');  
             }  
             sb.append(column);  
         }  
         return sb.toString();
    }  
    /** 
     * 获取用于Where的 有值字段表 
     * 目前仅提供2中类型的字段支持（字符串，数字）
     * @return 
     */  
    public List<WhereColumn> returnWhereColumnsName() {  
        Field[] fields = this.getClass().getDeclaredFields();  
        List<WhereColumn> columnList = new ArrayList<WhereColumn>(fields.length);  
        for(Field field : fields) {  
            if(field.isAnnotationPresent(Column.class) && !notContainField(field))   
                columnList.add(new WhereColumn(field.getName(), field.getGenericType().equals(String.class),isNull(field)));  
        }  
        return columnList;  
    }  
    /** 
     * Where条件信息 
     * @author 
     */  
    public class WhereColumn {  
        public String name;  
        public Boolean isString;
        public Boolean isNull;//包括null和空字符串
        public WhereColumn(String name,Boolean isString,Boolean isNull) {  
            this.name = name;  
            this.isString = isString; 
            this.isNull=isNull;
        }  
    }  
    /** 
     * 用于获取Insert的字段累加 
     * @return 
     */  
    public String returnInsertColumnsName() { 
    	caculationColumnList();
        StringBuilder sb = new StringBuilder();  
        List<String> list = columnMap.get(this.getClass());  
        Integer i = 0;  
        for(String column : list) {  
            if(notContainField(column)){
            	  continue;
            } 
            if(i++ != 0){
            	sb.append(',');  
            }  
            sb.append(column);  
        }  
        return sb.toString();  
    }  
      
    /** 
     * 用于获取Insert的字段映射累加 
     * @return 
     */  
    public String returnInsertColumnsDefine() { 
    	caculationColumnList();
        StringBuilder sb = new StringBuilder();  
        List<String> list = columnMap.get(this.getClass());  
        int i = 0;  
        for(String column : list) {  
            if(notContainField(column)){
            	continue; 
            }  
            if(i++ != 0){
            	sb.append(',');            	
            }  
            sb.append("#{").append(column).append('}');  
        }  
        return sb.toString();  
    }  
      
    /** 
     * 用于获取Update Set的字段累加 
     * @return 
     */  
    public String returnUpdateSet() {  
        StringBuilder sb = new StringBuilder();  
        List<String> list = columnMap.get(this.getClass());  
        Integer i = 0;  
        for(String column : list) {  
            if(notContainField(column)) {
            	continue;             	
            } 
            if(i++ != 0)  
                sb.append(',');  
            sb.append(column).append("=#{").append(column).append('}');  
        }  
        return sb.toString();  
    }  
    /** 
     * 转化POJO为JSON格式 
     * 需要org.json包支持,可以在json官网下载源码,或自己实现json编码 
     * @return 
     */  
    public String toJSONString() {  
        JSONObject json = new JSONObject(this);  
        return json.toString();  
    }  
    /** 
     * 打印类字段信息 
     */  
    @Override  
    public String toString() {  
        Field[] fields = this.getClass().getDeclaredFields();  
        StringBuilder sb = new StringBuilder();  
        sb.append('[');  
        for(Field f : fields) {  
            if(Modifier.isStatic(f.getModifiers()) || Modifier.isFinal(f.getModifiers()))  
                continue;  
            Object value = null;  
            try {  
                f.setAccessible(true);  
                value = f.get(this);  
            } catch (IllegalArgumentException e) {  
                e.printStackTrace();  
            } catch (IllegalAccessException e) {  
                e.printStackTrace();  
            }  
            if(value != null)  
                sb.append(f.getName()).append('=').append(value).append(',');  
        }  
        sb.append(']');  
        return sb.toString();  
    }  
}  